local cookie = require "plugins.filter.cookie"

local util = require "plugins.common.util"
local log =  require("core.log").new("request_matcher: ")
local find = ngx.re.find
local get_var = require("resty.ngxvar").fetch

local _M = {}
local tester = {}
local mt = { __index = _M }

--检测方法
function _M.test(self,matcher)
    if matcher == nil then
        return false
    end

    for name, v in pairs(matcher) do
        --log.error("-1---1---1-",name,type(tester[name]))
        if tester[name] ~= nil then
            --local ret = tester[name](self,v)

            --if  name == "IPWhiteList" and ret == true then
            --    return false
            --elseif name ~= "IPWhiteList" and  ret ~= true then
            --    return false
            --end
            -- elseif name ~= "IPWhiteList" and  ret ~= true then
            --     return false
            -- end

             if tester[name](self,v) ~= true then
                 return false
             end
        end
    end

    return true
end

--检测变量的基础方法
function _M.test_var(match_operator, match_value, target_var)
    if match_operator == '≈' then
        --ngx.log(ngx.WARN,"------,target url: ",target_var,"  ;match-value: ",match_value,  ngx.re.find(target_var, match_value, 'isjo'))
        if type(target_var) == 'string' and find(target_var, match_value, 'isjo') ~= nil then
            return true
        end
    elseif match_operator == '!≈' then
        if type(target_var) ~= 'string' or find(target_var, match_value, 'isjo') == nil then
            return true
        end
    elseif match_operator == "=" then
        --ngx.log(ngx.WARN,"target-value: ",type(target_var)," ,match-value: ",type(match_value),target_var==match_value)
        if target_var == match_value then
            return true
        end
    elseif match_operator == "*" then
        return true
    elseif match_operator == "!=" then
        if target_var ~= match_value then
            return true
        end
    elseif match_operator == 'Exist' then
        if target_var ~= nil then
            return true
        end
    elseif match_operator == '!Exist' then
        if target_var == nil then
            return true
        end
    elseif match_operator == '!' then
        if target_var == nil then
            return true
        end
    end

    return false
end


function _M.test_many_var(var_table, condition)

    local test_var = _M.test_var

    local name_operator = condition['name_operator']
    local name_value = condition['name_value']
    local operator = condition['operator']
    local value = condition['value']

    for k, v in pairs(var_table) do
        if test_var(name_operator, name_value, k) == true then
            if test_var(operator, value, v) == true then
                return true
            end
        end
    end

    return false
end

--URI检测方法
function _M.test_uri(self,condition)
    local uri = get_var("uri");
    return _M.test_var(condition['operator'], condition['value'], uri)
end

--URL检测方法
function _M.test_url(self,condition)
    local url = get_var("http_host") .. get_var("request_uri");
    --ngx.log(ngx.WARN,"url: ",url,"  ;cond-url: ",condition['value'])
    return _M.test_var(condition['operator'], condition['value'], url)
end

--IP检测方法
function _M.test_ip(self,condition)
    local client_ip = util.get_client_ip(self.get_ip_mode);
    return _M.test_var(condition['operator'], condition['value'], client_ip)
end

--app检测方法
function _M.test_app(self,condition)
    local app = get_var(self.app_key);
    return _M.test_var(condition['operator'], condition['value'], app)
end

--location检测方法
function _M.test_location(self,condition)
    local location = get_var("location");
    return _M.test_var(condition['operator'], condition['value'], location)
end

--IP白名单检测方法
function _M.test_ip_whitelist(self,condition)
    --log.error(get_client_ip(self))
    local client_ip = util.get_client_ip(self.get_ip_mode);

    if client_ip ~= nil then
        local ips = condition['ips']:split(',')
        for idx, ip in ipairs(ips) do
            --ngx.log(ngx.WARN,"client ip --- :",client_ip , ip)
            if (client_ip == ip) then
                return true;
            end
        end
    end
    return false;
end

--user agent检测方法
function _M.test_ua(self,condition)
    local http_user_agent = get_var("http_user_agent") ;
    return _M.test_var(condition['operator'], condition['value'], http_user_agent)
end

--referer检测方法
function _M.test_referer(self,condition)
    local http_referer = get_var("http_referer");
    return _M.test_var(condition['operator'], condition['value'], http_referer)
end

--uncompleted
function _M.test_method(self,condition)
    local method_name = ngx.req.get_method()
    return _M.test_var(condition['operator'], condition['value'], method_name)
end

--参数检测方法
function _M.test_args(self,condition)

    local test_var = _M.test_var

    local name_operator = condition['name_operator']
    local name_value = condition['name_value']
    local operator = condition['operator']
    local value = condition['value']

    --uri后面的参数检测
    for k, v in pairs(ngx.req.get_uri_args()) do
        --ngx.log(ngx.WARN,"------,key: ",k,"  ;name-value: ",name_value," ,target-value: ",v," ,match-value: ",value)

        if test_var(name_operator, name_value, k) == true then
            if type(v) == "table" then
                for arg_idx, arg_value in ipairs(v) do
                    if test_var(operator, value, arg_value) == true then
                        return true
                    end
                end
            else

                if test_var(operator, value, v) == true then
                    return true
                end
            end
        end
    end

    ngx.req.read_body()
    --确保主体没有缓存到主体文件中
    if ngx.req.get_body_file() ~= nil then
        return false
    end

    local body_args, err = ngx.req.get_post_args()
    if body_args == nil then
        ngx.say("failed to get post args: ", err)
        return false
    end

    --检测在主体的参数
    for k, v in pairs(body_args) do
        if test_var(name_operator, name_value, k) == true then
            if type(v) == "table" then
                for arg_idx, arg_value in ipairs(v) do
                    if test_var(operator, value, arg_value) == true then
                        return true
                    end
                end
            else
                if test_var(operator, value, v) == true then
                    return true
                end
            end
        end
    end

    return false
end

function _M.test_host(self,condition)
    local hostname = get_var("host")
    return _M.test_var(condition['operator'], condition['value'], hostname)
end

function _M.test_header(self,condition)
    local header_table = ngx.req.get_headers()
    return _M.test_many_var(header_table, condition)
end

function _M.test_cookie(self,condition)
    local cookie_obj, err = cookie:new()
    local cookie_table = cookie_obj:get_all()

    if cookie_table == nil then
        cookie_table = {}
    end
    return _M.test_many_var(cookie_table, condition)
end

tester["URI"] = _M.test_uri
tester["APP"] = _M.test_app
tester["LOCATION"] = _M.test_location
tester["URL"] = _M.test_url
--tester["IP"] = _M.test_ip
--tester["IPWhiteList"] = _M.test_ip_whitelist
--tester["IPBlackList"] = _M.test_ip_whitelist
tester["UserAgent"] = _M.test_ua
tester["Method"] = _M.test_method
tester["Args"] = _M.test_args
tester["Referer"] = _M.test_referer
tester["Host"] = _M.test_host
tester["Header"] = _M.test_header
tester["Cookie"] = _M.test_cookie

function _M.new(args,app_key)
    args = args or {"remote_addr"}
    app_key = app_key or "app_name"
    return setmetatable({get_ip_mode = args,app_key = app_key},mt)
end

return _M
